home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / plug-ins / common / gif.c < prev    next >
Encoding:
Text File  |  2003-05-14  |  59.9 KB  |  2,454 lines

  1. /* GIF saving file filter for The GIMP version 1.0/1.1
  2.  *
  3.  *    - Adam D. Moss
  4.  *    - Peter Mattis
  5.  *    - Spencer Kimball
  6.  *
  7.  *      Based around original GIF code by David Koblas.
  8.  *
  9.  *
  10.  * Version 3.0.2 - 99/04/25
  11.  *                        Adam D. Moss - <adam@gimp.org> <adam@foxbox.org>
  12.  */
  13. /*
  14.  * This filter uses code taken from the "giftopnm" and "ppmtogif" programs
  15.  *    which are part of the "netpbm" package.
  16.  */
  17. /*
  18.  *  "The Graphics Interchange Format(c) is the Copyright property of
  19.  *  CompuServe Incorporated.  GIF(sm) is a Service Mark property of
  20.  *  CompuServe Incorporated." 
  21.  */
  22. /* Copyright notice for GIF code from which this plugin was long ago     */
  23. /* derived (David Koblas has granted permission to relicense):           */
  24. /* +-------------------------------------------------------------------+ */
  25. /* | Copyright 1990, 1991, 1993, David Koblas.  (koblas@extra.com)     | */
  26. /* +-------------------------------------------------------------------+ */
  27.  
  28. /*
  29.  * REVISION HISTORY
  30.  *
  31.  * 99/04/25
  32.  * 3.00.02 - Save the comment back onto the image as a persistent
  33.  *           parasite if the comment was edited.
  34.  *
  35.  * 99/03/30
  36.  * 3.00.01 - Round image timing to nearest 10ms instead of
  37.  *           truncating.  Insert a mandatory 10ms minimum delay
  38.  *           for the frames of looping animated GIFs, to avoid
  39.  *           generating an evil CPU-sucking animation that 'other'
  40.  *           GIF-animators sometimes like to save.
  41.  *
  42.  * 99/03/20
  43.  * 3.00.00 - GIF-loading code moved to separate plugin.
  44.  *
  45.  * 99/02/22
  46.  * 2.01.02 - Don't show a progress bar when loading non-interactively
  47.  *
  48.  * 99/01/23
  49.  * 2.01.01 - Use a text-box to permit multi-line comments.  Don't
  50.  *           try to write comment blocks which are longer than
  51.  *           permitted.
  52.  *
  53.  * 98/10/09
  54.  * 2.01.00 - Added support for persistent GIF Comments through
  55.  *           the GIMP 1.1 GimpParasite mechanism where available.
  56.  *           Did some user-interface tweaks.
  57.  *           Fixed a bug when trying to save a GIF smaller
  58.  *           than five pixels high as interlaced.
  59.  *
  60.  * 98/09/28
  61.  * 2.00.05 - Fixed TigerT's Infinite GIF Bug.  Icky one.
  62.  *
  63.  * 98/09/15
  64.  * 2.00.04 - The facility to specify the background colour of
  65.  *           a transparent/animated GIF for non-transparent
  66.  *           viewers now works very much more consistantly.
  67.  *
  68.  *           The only situations in which it will fail to work
  69.  *           as expected now are those where file size can be reduced
  70.  *           (abeit not by much, as the plugin is sometimes more pessimistic
  71.  *           than it need be) by re-using an existing unused colour
  72.  *           index rather than using another bit per pixel in the
  73.  *           encoded file.  That will never be an issue with an image
  74.  *           which was freshly converted from RGB to INDEXED with the
  75.  *           Quantize option, as that option removes any unused colours
  76.  *           from the image.
  77.  *
  78.  *           Let me know if you find the consistancy/size tradeoff more
  79.  *           annoying than helpful and I can adjust it.  IMHO it is too
  80.  *           arcane a feature to present to any user as a runtime option.
  81.  *
  82.  * 98/05/18
  83.  * 2.00.03 - If we did manage to decode at least one frame of a
  84.  *           gif, be sure to display the resulting image even if
  85.  *           it terminated abruptly.
  86.  *
  87.  * 98/04/28
  88.  * 2.00.02 - Fixed a bug with (ms) tag parsing.
  89.  *
  90.  * 98/03/16
  91.  * 2.00.01 - Fixed a long-standing bug when loading GIFs which layer
  92.  *           opaque frames onto transparent ones.
  93.  *
  94.  * 98/03/15
  95.  * 2.00.00 - No longer beta.  Uses the current GIMP brush background
  96.  *           colour as the transparent-index colour for viewers that
  97.  *           don't know about transparency, instead of magenta.  Note
  98.  *           that this is by no means likely to actually work, but
  99.  *           is more likely to do so if your image has been freshly
  100.  *           to-index'd before saving.
  101.  *
  102.  *           Also added some analysis to gif-reading to prevent the
  103.  *           number of encoded bits being pumped up inadvertantly for
  104.  *           successive load/saves of the same image.  [Adam]
  105.  *
  106.  * 97/12/11
  107.  * 1.99.18 - Bleh.  Disposals should specify how the next frame will
  108.  *           be composed with this frame, NOT how this frame will
  109.  *           be composed with the previous frame.  Fixed.  [Adam]
  110.  *
  111.  * 97/11/30
  112.  * 1.99.17 - No more bogus transparency indices in animated GIFs,
  113.  *           hopefully.  Saved files are better-behaved, sometimes
  114.  *           smaller.  [Adam]
  115.  *
  116.  * 97/09/29
  117.  * 1.99.16 - Added a dialog for the user to choose what to do if
  118.  *           one of the layers of the image extends beyond the image
  119.  *           borders - crop or cancel.  Added code behind it.
  120.  *
  121.  *           Corrected the number of bits for the base image to be
  122.  *           on the generous side.  Hopefully we can no longer generate
  123.  *           GIFs which make XV barf.
  124.  *
  125.  *           Now a lot more careful about whether we choose to encode
  126.  *           as a GIF87a or a GIF89a.  Hopefully does everything by the
  127.  *           book.  It should now be nigh-on impossible to torture the
  128.  *           plugin into generating a GIF which isn't extremely well
  129.  *           behaved with respect to the GIF89a specification.
  130.  *
  131.  *           Fixed(?) a lot of dialog callback details, should now be
  132.  *           happy with window deletion (GTK+970925).  Fixed the
  133.  *           cancellation of a save.  [Adam]
  134.  *
  135.  * 97/09/16
  136.  * 1.99.15 - Hey!  We can now cope with loading images which change
  137.  *           colourmap between frames.  This plugin will never save
  138.  *           such abominations of nature while I still live, though.
  139.  *           There should be no noncorrupt GIF in the universe which
  140.  *           GIMP can't load and play now.  [Adam]
  141.  *
  142.  * 97/09/14
  143.  * 1.99.14 - Added a check for layers whose extents don't lay
  144.  *           within the image boundaries, which would make it a
  145.  *           lot harder to generate badly-behaved GIFs.  Doesn't
  146.  *           do anything about it yet, but it should crop all layers
  147.  *           to the image boundaries.  Also, there's now a (separate)
  148.  *           animation-preview plugin!  [Adam]
  149.  *
  150.  * 97/08/29
  151.  * 1.99.13 - Basic ability to embed GIF comments within saved images.
  152.  *           Fixed a bug with encoding the number of loops in a GIF file -
  153.  *           would have been important, but we're not using that feature
  154.  *           yet anyway.  ;)
  155.  *           Subtly improved dialog layout a little. [Adam]
  156.  *
  157.  * 97/07/25
  158.  * 1.99.12 - Fixed attempts to load GIFs which don't exist.  Made a
  159.  *           related cosmetic adjustment. [Adam]
  160.  *
  161.  * 97/07/10
  162.  * 1.99.11 - Fixed a bug with loading and saving GIFs where the bottom
  163.  *           layer wasn't the same size as the image. [Adam]
  164.  *
  165.  * 97/07/06
  166.  * 1.99.10 - New 'save' dialog, now most of the default behaviour of
  167.  *           animated GIF saving is user-settable (looping, default
  168.  *           time between frames, etc.)
  169.  *           PDB entry for saving is no longer compatible.  Fortunately
  170.  *           I don't think that anyone is using file_gif_save in
  171.  *           scripts.  [Adam]
  172.  *
  173.  * 97/07/05
  174.  * 1.99.9  - More animated GIF work: now loads and saves frame disposal
  175.  *           information.  This is neat and will also allow some delta
  176.  *           stuff in the future.
  177.  *           The disposal-method is kept in the layer name, like the timing
  178.  *           info.
  179.  *           (replace) - this frame replaces whatever else has been shown
  180.  *                       so far.
  181.  *           (combine) - this frame builds apon the previous frame.
  182.  *           If a disposal method is not specified, it is assumed to mean
  183.  *           "don't care."  [Adam]
  184.  *
  185.  * 97/07/04
  186.  * 1.99.8  - Can save per-frame timing information too, now.  The time
  187.  *           for which a frame is visible is specified within the layer name
  188.  *           as i,e. (250ms).  If a frame doesn't have this timing value
  189.  *           it defaults to lasting 100ms. [Adam]
  190.  *
  191.  * 97/07/02
  192.  * 1.99.7  - For animated GIFs, fixed the saving of timing information for
  193.  *           frames which couldn't be made transparent.
  194.  *           Added the loading of timing information into the layer
  195.  *           names.  Adjusted GIMP's GIF magic number very slightly. [Adam]
  196.  *
  197.  * 97/06/30
  198.  * 1.99.6  - Now saves GRAY and GRAYA images, albeit not always
  199.  *           optimally (yet). [Adam]
  200.  *
  201.  * 97/06/25
  202.  * 1.99.5  - Good, the transparancy-on-big-architectures bug is
  203.  *           fixed.  Cleaned up some stuff.
  204.  *           (Adam D. Moss, adam@foxbox.org)
  205.  *
  206.  * 97/06/23
  207.  * 1.99.4  - Trying to fix some endianness/word-size problems with
  208.  *           transparent gif-saving on some architectures... does
  209.  *           this help?  (Adam D. Moss, adam@foxbox.org)
  210.  *
  211.  * 97/05/18
  212.  * 1.99.3  - Fixed the problem with GIFs getting loop extensions even
  213.  *           if they only had one frame (thanks to Zach for noticing -
  214.  *           git!  :) )  (Adam D. Moss, adam@foxbox.org)
  215.  *
  216.  * 97/05/17
  217.  * 1.99.2  - Can now save animated GIFs.  Correctly handles saving of
  218.  *           image offsets.  Uses N*tscape extentions to loop infinitely.
  219.  *           Some notable shortcomings - see TODO list below.
  220.  *           (Adam D. Moss, adam@foxbox.org)
  221.  *
  222.  * 97/05/16
  223.  * 1.99.1  - Implemented image offsets in animated GIF loading.  Requires
  224.  *           a fix to gimp_layer_translate in libgimp/gimplayer.c if used
  225.  *           with GIMP versions <= 0.99.10.  Started work on saving animated
  226.  *           GIFs.  Started TODO list.  (Adam D. Moss, adam@foxbox.org)
  227.  *
  228.  * 97/05/15
  229.  * 1.99.0  - Started revision log.  GIF plugin now loads/saves INDEXED
  230.  *           and INDEXEDA images with correct transparency where possible.
  231.  *           Loads multi-image (animated) GIFs as a framestack implemented
  232.  *           in GIMP layers.  Some bug fixes to original code, some new bugs
  233.  *           cheerfully added.  (Adam D. Moss, adam@foxbox.org)
  234.  *
  235.  * Previous versions - load/save INDEXED images.
  236.  *           (Peter Mattis & Spencer Kimball, gimp@scam.xcf.berkeley.edu)
  237.  */
  238.  
  239. /*
  240.  * TODO (more *'s means more important!)
  241.  *
  242.  * - PDB stuff for comments
  243.  *
  244.  * - 'requantize' option for INDEXEDA images which really have 256 colours
  245.  *   in them
  246.  *
  247.  * - Be a bit smarter about finding unused/superfluous colour indices for
  248.  *   lossless colour crunching of INDEXEDA images.  (Specifically, look
  249.  *   for multiple indices which correspond to the same physical colour.)
  250.  *
  251.  * - Tidy up parameters for the GIFEncode routines
  252.  *
  253.  * - Remove unused colourmap entries for GRAYSCALE images.
  254.  *
  255.  * - Button to activate the animation preview plugin from the GIF-save
  256.  *   dialog.
  257.  *
  258.  */
  259.  
  260. #include "config.h"
  261.  
  262. #include <stdio.h>
  263. #include <stdlib.h>
  264. #include <string.h>
  265. #include <ctype.h>
  266.  
  267. #include <libgimp/gimp.h>
  268. #include <libgimp/gimpui.h>
  269.  
  270. #include "libgimp/stdplugins-intl.h"
  271.  
  272.  
  273. /* uncomment the line below for a little debugging info */
  274. /* #define GIFDEBUG yesplease */
  275.  
  276. /* Does the version of GIMP we're compiling for support
  277.    data attachments to images?  ('Parasites') */
  278. #ifdef GIMP_HAVE_PARASITES
  279. #define FACEHUGGERS aieee
  280. #endif
  281. /* PS: I know that technically facehuggers aren't parasites,
  282.    the pupal-forms are.  But facehuggers are ky00te. */
  283.  
  284. enum
  285. {
  286.   DISPOSE_UNSPECIFIED,
  287.   DISPOSE_COMBINE,
  288.   DISPOSE_REPLACE
  289. };
  290.  
  291. typedef struct
  292. {
  293.   gint interlace;
  294.   gint save_comment;
  295.   gint loop;
  296.   gint default_delay;
  297.   gint default_dispose;
  298. } GIFSaveVals;
  299.  
  300. typedef struct
  301. {
  302.   gint run;
  303. } GIFSaveInterface;
  304.  
  305.  
  306.  
  307. /* Declare some local functions.
  308.  */
  309. static void   query                    (void);
  310. static void   run                      (gchar   *name,
  311.                     gint     nparams,
  312.                     GimpParam  *param,
  313.                     gint    *nreturn_vals,
  314.                     GimpParam **return_vals);
  315. static gint   save_image               (gchar   *filename,
  316.                     gint32   image_ID,
  317.                     gint32   drawable_ID,
  318.                     gint32   orig_image_ID);
  319.  
  320. static gboolean boundscheck            (gint32 image_ID);
  321. static gboolean badbounds_dialog       (void);
  322.  
  323. static void   cropok_callback          (GtkWidget *widget, gpointer   data);
  324.  
  325. static gint   save_dialog              (gint32 image_ID);
  326.  
  327. static void   save_ok_callback         (GtkWidget *widget, gpointer   data);
  328. static void   comment_entry_callback   (GtkWidget *widget, gpointer   data);
  329.  
  330.  
  331. static gboolean comment_was_edited = FALSE;
  332.  
  333. static gboolean can_crop = FALSE;
  334. static GimpRunModeType run_mode;
  335. #ifdef FACEHUGGERS
  336. GimpParasite * comment_parasite = NULL;
  337. #endif
  338.  
  339. /* For compression code */
  340. static gint Interlace;
  341.  
  342.  
  343. GimpPlugInInfo PLUG_IN_INFO =
  344. {
  345.   NULL,  /* init_proc  */
  346.   NULL,  /* quit_proc  */
  347.   query, /* query_proc */
  348.   run,   /* run_proc   */
  349. };
  350.  
  351. static GIFSaveVals gsvals =
  352. {
  353.   FALSE,   /* interlace                            */
  354.   TRUE,    /* save comment                         */
  355.   TRUE,    /* loop infinitely                      */
  356.   100,     /* default_delay between frames (100ms) */
  357.   0        /* default_dispose = "don't care"       */
  358. };
  359.  
  360. static GIFSaveInterface gsint =
  361. {
  362.   FALSE   /*  run  */
  363. };
  364.  
  365.  
  366. MAIN ()
  367.  
  368. static void
  369. query (void)
  370. {
  371.   static GimpParamDef save_args[] =
  372.   {
  373.     { GIMP_PDB_INT32,    "run_mode",        "Interactive, non-interactive" },
  374.     { GIMP_PDB_IMAGE,    "image",           "Image to save" },
  375.     { GIMP_PDB_DRAWABLE, "drawable",        "Drawable to save" },
  376.     { GIMP_PDB_STRING,   "filename",        "The name of the file to save the image in" },
  377.     { GIMP_PDB_STRING,   "raw_filename",    "The name entered" },
  378.     { GIMP_PDB_INT32,    "interlace",       "Try to save as interlaced" },
  379.     { GIMP_PDB_INT32,    "loop",            "(animated gif) loop infinitely" },
  380.     { GIMP_PDB_INT32,    "default_delay",   "(animated gif) Default delay between framese in milliseconds" },
  381.     { GIMP_PDB_INT32,    "default_dispose", "(animated gif) Default disposal type (0=`don't care`, 1=combine, 2=replace)" }
  382.   };
  383.   static gint nsave_args = sizeof (save_args) / sizeof (save_args[0]);
  384.  
  385.   gimp_install_procedure ("file_gif_save",
  386.                           "saves files in Compuserve GIF file format",
  387.                           "Save a file in Compuserve GIF format, with "
  388.               "possible animation, transparency, and comment.  "
  389.               "To save an animation, operate on a multi-layer "
  390.               "file.  The plug-in will intrepret <50% alpha as "
  391.               "transparent.  When run non-interactively, the "
  392.               "value for the comment is taken from the "
  393.               "'gimp-comment' parasite.  ",
  394.                           "Spencer Kimball, Peter Mattis, Adam Moss, David Koblas",
  395.                           "Spencer Kimball, Peter Mattis, Adam Moss, David Koblas",
  396.                           "1995-1997",
  397.                           "<Save>/GIF",
  398.               "INDEXED*, GRAY*",
  399.                           GIMP_PLUGIN,
  400.                           nsave_args, 0,
  401.                           save_args, NULL);
  402.  
  403.   gimp_register_save_handler ("file_gif_save",
  404.                   "gif",
  405.                   "");
  406. }
  407.  
  408. static void
  409. run (gchar   *name,
  410.      gint     nparams,
  411.      GimpParam  *param,
  412.      gint    *nreturn_vals,
  413.      GimpParam **return_vals)
  414. {
  415.   static GimpParam values[2];
  416.   GimpPDBStatusType   status = GIMP_PDB_SUCCESS;
  417.   gint32        image_ID;
  418.   gint32        drawable_ID;
  419.   gint32        orig_image_ID;
  420.   GimpExportReturnType export = GIMP_EXPORT_CANCEL;
  421.  
  422.   run_mode = param[0].data.d_int32;
  423.  
  424.   *nreturn_vals = 1;
  425.   *return_vals  = values;
  426.   values[0].type          = GIMP_PDB_STATUS;
  427.   values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
  428.  
  429.   if (strcmp (name, "file_gif_save") == 0)
  430.     {
  431.       INIT_I18N_UI();
  432.       gimp_ui_init ("gif", FALSE);
  433.  
  434.       image_ID    = orig_image_ID = param[1].data.d_int32;
  435.       drawable_ID = param[2].data.d_int32;
  436.  
  437.       /*  eventually export the image */ 
  438.       switch (run_mode)
  439.     {
  440.     case GIMP_RUN_INTERACTIVE:
  441.     case GIMP_RUN_WITH_LAST_VALS:
  442.       export = gimp_export_image (&image_ID, &drawable_ID, "GIF", 
  443.                       (GIMP_EXPORT_CAN_HANDLE_INDEXED |
  444.                        GIMP_EXPORT_CAN_HANDLE_GRAY | 
  445.                        GIMP_EXPORT_CAN_HANDLE_ALPHA  |
  446.                        GIMP_EXPORT_CAN_HANDLE_LAYERS_AS_ANIMATION));
  447.       if (export == GIMP_EXPORT_CANCEL)
  448.         {
  449.           values[0].data.d_status = GIMP_PDB_CANCEL;
  450.           return;
  451.         }
  452.       break;
  453.     default:
  454.       break;
  455.     }
  456.  
  457.       if (boundscheck (image_ID))
  458.     /* The image may or may not have had layers out of
  459.        bounds, but the user didn't mind cropping it down. */
  460.     {
  461.       switch (run_mode)
  462.         {
  463.         case GIMP_RUN_INTERACTIVE:
  464.           /*  Possibly retrieve data  */
  465.           gimp_get_data ("file_gif_save", &gsvals);
  466.         
  467.           /*  First acquire information with a dialog  */
  468.           if (! save_dialog (image_ID))
  469.         status = GIMP_PDB_CANCEL;
  470.           break;
  471.           
  472.         case GIMP_RUN_NONINTERACTIVE:
  473.           /*  Make sure all the arguments are there!  */
  474.           if (nparams != 9)
  475.         {
  476.           status = GIMP_PDB_CALLING_ERROR;
  477.         }
  478.           else
  479.         {
  480.           gsvals.interlace       = (param[5].data.d_int32) ? TRUE : FALSE;
  481.           gsvals.save_comment    = TRUE;  /*  no way to to specify that through the PDB  */
  482.           gsvals.loop            = (param[6].data.d_int32) ? TRUE : FALSE;
  483.           gsvals.default_delay   = param[7].data.d_int32;
  484.           gsvals.default_dispose = param[8].data.d_int32;
  485.         }
  486.           break;
  487.           
  488.         case GIMP_RUN_WITH_LAST_VALS:
  489.           /*  Possibly retrieve data  */
  490.           gimp_get_data ("file_gif_save", &gsvals);
  491.           break;
  492.           
  493.         default:
  494.           break;
  495.         }
  496.  
  497.       if (status == GIMP_PDB_SUCCESS)
  498.         {
  499.           if (save_image (param[3].data.d_string,
  500.                   image_ID,
  501.                   drawable_ID,
  502.                   orig_image_ID))
  503.         {
  504.           /*  Store psvals data  */
  505.           gimp_set_data ("file_gif_save", &gsvals, sizeof (GIFSaveVals));
  506.         }
  507.           else
  508.         {
  509.           status = GIMP_PDB_EXECUTION_ERROR;
  510.         }
  511.         }
  512.     }
  513.       else /* Some layers were out of bounds and the user wishes
  514.           to abort.  */
  515.     {
  516.       status = GIMP_PDB_CANCEL;
  517.     }
  518.  
  519.       if (export == GIMP_EXPORT_EXPORT)
  520.     gimp_image_delete (image_ID);
  521.     }
  522.  
  523.   values[0].data.d_status = status;
  524. }
  525.  
  526. #define MAXCOLORMAPSIZE  256
  527.  
  528. #define INTERLACE          0x40
  529. #define LOCALCOLORMAP      0x80
  530.  
  531. #define GRAYSCALE        1
  532. #define COLOR            2
  533.  
  534. typedef guchar CMap[3][MAXCOLORMAPSIZE];
  535.  
  536.  
  537. gint   verbose = FALSE;
  538. gchar *globalcomment = NULL;
  539.  
  540.  
  541.  
  542. /* ppmtogif.c - read a portable pixmap and produce a GIF file
  543. **
  544. ** Based on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>. A
  545. ** Lempel-Ziv compression based on "compress".
  546. **
  547. ** Modified by Marcel Wijkstra <wijkstra@fwi.uva.nl>
  548. **
  549. **
  550. ** Copyright (C) 1989 by Jef Poskanzer.
  551. **
  552. ** Permission to use, copy, modify, and distribute this software and its
  553. ** documentation for any purpose and without fee is hereby granted, provided
  554. ** that the above copyright notice appear in all copies and that both that
  555. ** copyright notice and this permission notice appear in supporting
  556. ** documentation.  This software is provided "as is" without express or
  557. ** implied warranty.
  558. **
  559. ** The Graphics Interchange Format(c) is the Copyright property of
  560. ** CompuServe Incorporated.  GIF(sm) is a Service Mark property of
  561. ** CompuServe Incorporated.
  562. */
  563.  
  564. #define MAXCOLORS 256
  565.  
  566. /*
  567.  * Pointer to function returning an int
  568.  */
  569. typedef int (*ifunptr) (int, int);
  570.  
  571. /*
  572.  * a code_int must be able to hold 2**BITS values of type int, and also -1
  573.  */
  574. typedef int code_int;
  575.  
  576. #ifdef SIGNED_COMPARE_SLOW
  577. typedef unsigned long int count_int;
  578. typedef unsigned short int count_short;
  579. #else /*SIGNED_COMPARE_SLOW */
  580. typedef long int count_int;
  581. #endif /*SIGNED_COMPARE_SLOW */
  582.  
  583.  
  584.  
  585. static int find_unused_ia_colour (guchar *pixels,
  586.                   int numpixels,
  587.                   int num_indices,
  588.                   int* colors);
  589.  
  590. void special_flatten_indexed_alpha (guchar *pixels,
  591.                     int *transparent,
  592.                     int *colors,
  593.                     int numpixels);
  594. static int colorstobpp (int);
  595. static int bpptocolors (int);
  596. static int GetPixel (int, int);
  597. static void BumpPixel (void);
  598. static int GIFNextPixel (ifunptr);
  599.  
  600. static void GIFEncodeHeader (FILE *, gboolean, int, int, int, int,
  601.                  int *, int *, int *, ifunptr);
  602. static void GIFEncodeGraphicControlExt (FILE *, int, int, int, int, int,
  603.                     int, int, int, int *, int *, int *,
  604.                     ifunptr);
  605. static void GIFEncodeImageData (FILE *, int, int, int, int, int, int,
  606.                 int *, int *, int *, ifunptr, gint, gint);
  607. static void GIFEncodeClose (FILE *, int, int, int, int, int, int,
  608.                 int *, int *, int *, ifunptr);
  609. static void GIFEncodeLoopExt (FILE *, guint);
  610. static void GIFEncodeCommentExt (FILE *, char *);
  611.  
  612. int rowstride;
  613. guchar *pixels;
  614. int cur_progress;
  615. int max_progress;
  616.  
  617. static void Putword (int, FILE *);
  618. static void compress (int, FILE *, ifunptr);
  619. static void output (code_int);
  620. static void cl_block (void);
  621. static void cl_hash (count_int);
  622. static void writeerr (void);
  623. static void char_init (void);
  624. static void char_out (int);
  625. static void flush_char (void);
  626.  
  627.  
  628.  
  629. static int find_unused_ia_colour (guchar *pixels,
  630.                   int numpixels,
  631.                   int num_indices,
  632.                   int* colors)
  633. {
  634.   int i;
  635.   gboolean ix_used[256];
  636.  
  637. #ifdef GIFDEBUG
  638.   g_print ("GIF: fuiac: Image claims to use %d/%d indices - finding free "
  639.        "index...\n", (int)(*colors),(int)num_indices);
  640. #endif
  641.  
  642.   for (i=0; i<256; i++)
  643.     {
  644.       ix_used[i] = (gboolean)FALSE;
  645.     }
  646.  
  647.   for (i=0; i<numpixels; i++)
  648.     {
  649.       if (pixels[i*2+1]) ix_used[pixels[i*2]] = (gboolean)TRUE;
  650.     }
  651.   
  652.   for (i=num_indices-1; i>=0; i--)
  653.     {
  654.       if (ix_used[i] == (gboolean)FALSE)
  655.     {
  656. #ifdef GIFDEBUG
  657.       g_print ("GIF: Found unused colour index %d.\n",(int)i);
  658. #endif
  659.       return i;
  660.     }
  661.     }
  662.  
  663.   /* Couldn't find an unused colour index within the number of
  664.      bits per pixel we wanted.  Will have to increment the number
  665.      of colours in the image and assign a transparent pixel there. */
  666.   if ((*colors) < 256)
  667.     {
  668.       (*colors)++;
  669.       g_print ("GIF: 2nd pass - Increasing bounds and using colour index %d.\n"
  670.            , (int) (*colors)-1);
  671.       return ((*colors)-1);
  672.     }
  673.   
  674.   g_message (_("GIF: Couldn't simply reduce colors further.\nSaving as opaque.\n"));
  675.   return (-1);
  676. }
  677.  
  678.  
  679. void
  680. special_flatten_indexed_alpha (guchar *pixels,
  681.                    int *transparent,
  682.                    int *colors,
  683.                    int numpixels)
  684. {
  685.   guint32 i;
  686.  
  687.   /* Each transparent pixel in the image is mapped to a uniform value for
  688.      encoding, if image already has <=255 colours */
  689.   
  690.   if ((*transparent) == -1) /* tough, no indices left for the trans. index */
  691.     {
  692.       for (i=0; i<numpixels; i++)
  693.     pixels[i] = pixels[i*2];
  694.     }
  695.   else  /* make transparent */
  696.     {
  697.       for (i=0; i<numpixels; i++)
  698.     {
  699.       if (!(pixels[i*2+1] & 128))
  700.         {
  701.           pixels[i] = (guchar)(*transparent);
  702.         }
  703.       else
  704.         {
  705.           pixels[i] = pixels[i*2];
  706.         }
  707.     }
  708.     }
  709.  
  710.  
  711.   /* Pixel data now takes half as much space (the alpha data has been
  712.      discarded) */
  713.   /*  pixels = g_realloc (pixels, numpixels);*/
  714. }
  715.  
  716.  
  717. int
  718. parse_ms_tag (char *str)
  719. {
  720.   gint sum = 0;
  721.   gint offset = 0;
  722.   gint length;
  723.  
  724.   length = strlen(str);
  725.  
  726. find_another_bra:
  727.  
  728.   while ((offset<length) && (str[offset]!='('))
  729.     offset++;
  730.   
  731.   if (offset>=length)
  732.     return(-1);
  733.  
  734.   if (!isdigit(str[++offset]))
  735.     goto find_another_bra;
  736.  
  737.   do
  738.     {
  739.       sum *= 10;
  740.       sum += str[offset] - '0';
  741.       offset++;
  742.     }
  743.   while ((offset<length) && (isdigit(str[offset])));  
  744.  
  745.   if (length-offset <= 2)
  746.     return(-3);
  747.  
  748.   if ((toupper(str[offset]) != 'M') || (toupper(str[offset+1]) != 'S'))
  749.     return(-4);
  750.  
  751.   return (sum);
  752. }
  753.  
  754.  
  755. int
  756. parse_disposal_tag (char *str)
  757. {
  758.   gint offset = 0;
  759.   gint length;
  760.  
  761.   length = strlen(str);
  762.  
  763.   while ((offset+9)<=length)
  764.     {
  765.       if (strncmp(&str[offset],"(combine)",9)==0) 
  766.     return(0x01);
  767.       if (strncmp(&str[offset],"(replace)",9)==0) 
  768.     return(0x02);
  769.       offset++;
  770.     }
  771.  
  772.   return (gsvals.default_dispose);
  773. }
  774.  
  775.  
  776. static gboolean
  777. boundscheck (gint32 image_ID)
  778. {
  779.   GimpDrawable *drawable;
  780.   gint32 *layers;   
  781.   gint nlayers;
  782.   gint i;
  783.   gint offset_x, offset_y;
  784.  
  785.   /* get a list of layers for this image_ID */
  786.   layers = gimp_image_get_layers (image_ID, &nlayers);  
  787.  
  788.  
  789.   /*** Iterate through the layers to make sure they're all ***/
  790.   /*** within the bounds of the image                      ***/
  791.  
  792.   for (i=0;i<nlayers;i++)
  793.     {
  794.       drawable = gimp_drawable_get (layers[i]);
  795.       gimp_drawable_offsets (layers[i], &offset_x, &offset_y);
  796.  
  797.       if ((offset_x < 0) ||
  798.       (offset_y < 0) ||
  799.       (offset_x+drawable->width > gimp_image_width(image_ID)) ||
  800.       (offset_y+drawable->height > gimp_image_height(image_ID)))
  801.     {
  802.       g_free (layers);
  803.       gimp_drawable_detach(drawable);
  804.  
  805.       /* Image has illegal bounds - ask the user what it wants to do */
  806.  
  807.       /* Do the crop if we can't talk to the user, or if we asked
  808.        * the user and they said yes. */
  809.       if ((run_mode == GIMP_RUN_NONINTERACTIVE) || badbounds_dialog ())
  810.         {
  811.           gimp_crop (image_ID,
  812.              gimp_image_width (image_ID), gimp_image_height (image_ID), 
  813.              0, 0);
  814.           return TRUE;
  815.         }
  816.       else
  817.         {
  818.           return FALSE;
  819.         }
  820.     }
  821.       else
  822.     gimp_drawable_detach(drawable);
  823.     }
  824.  
  825.   g_free (layers);
  826.  
  827.   return TRUE;
  828. }
  829.  
  830.  
  831. static gint
  832. save_image (gchar  *filename,
  833.         gint32  image_ID,
  834.         gint32  drawable_ID,
  835.         gint32  orig_image_ID)
  836. {
  837.   GimpPixelRgn pixel_rgn;
  838.   GimpDrawable *drawable;
  839.   GimpImageType drawable_type;
  840.   FILE *outfile;
  841.   int Red[MAXCOLORS];
  842.   int Green[MAXCOLORS];
  843.   int Blue[MAXCOLORS];
  844.   guchar *cmap;
  845.   guint rows, cols;
  846.   int BitsPerPixel, liberalBPP=0, useBPP=0;
  847.   int colors;
  848.   char *temp_buf;
  849.   int i;
  850.   int transparent;
  851.   gint offset_x, offset_y;
  852.  
  853.   gint32 *layers;   
  854.   int nlayers;
  855.  
  856.   gboolean is_gif89 = FALSE;
  857.  
  858.   int Delay89;
  859.   int Disposal;
  860.   char *layer_name;
  861.  
  862.   unsigned char bgred, bggreen, bgblue;
  863.  
  864.  
  865. #ifdef FACEHUGGERS
  866.   /* Save the comment back to the ImageID, if appropriate */
  867.   if (globalcomment != NULL && comment_was_edited)
  868.     {
  869.       comment_parasite = gimp_parasite_new ("gimp-comment",
  870.                         GIMP_PARASITE_PERSISTENT,
  871.                         strlen (globalcomment)+1,
  872.                         (void*) globalcomment);
  873.       gimp_image_parasite_attach (orig_image_ID, comment_parasite);
  874.       gimp_parasite_free (comment_parasite);
  875.       comment_parasite = NULL;
  876.     }
  877. #endif
  878.  
  879.  
  880.   /* get a list of layers for this image_ID */
  881.   layers = gimp_image_get_layers (image_ID, &nlayers);  
  882.  
  883.  
  884.   drawable_type = gimp_drawable_type (layers[0]);
  885.  
  886.  
  887.   /* If the image has multiple layers (i.e. will be animated), a comment,
  888.      or transparency, then it must be encoded as a GIF89a file, not a vanilla
  889.      GIF87a. */
  890.   if (nlayers > 1)
  891.     is_gif89 = TRUE;
  892.  
  893.   if (gsvals.save_comment)
  894.     is_gif89 = TRUE;
  895.  
  896.   switch (drawable_type)
  897.     {
  898.     case GIMP_INDEXEDA_IMAGE:
  899.       is_gif89 = TRUE;
  900.     case GIMP_INDEXED_IMAGE:
  901.       cmap = gimp_image_get_cmap (image_ID, &colors);
  902.       
  903.       gimp_palette_get_background(&bgred, &bggreen, &bgblue);
  904.  
  905.       for (i = 0; i < colors; i++)
  906.     {
  907.       Red[i] = *cmap++;
  908.       Green[i] = *cmap++;
  909.       Blue[i] = *cmap++;
  910.     }
  911.       for ( ; i < 256; i++)
  912.     {
  913.       Red[i] = bgred;
  914.       Green[i] = bggreen;
  915.       Blue[i] = bgblue;
  916.     }
  917.       break;
  918.     case GIMP_GRAYA_IMAGE:
  919.       is_gif89 = TRUE;
  920.     case GIMP_GRAY_IMAGE:
  921.       colors = 256;                   /* FIXME: Not ideal. */
  922.       for ( i = 0;  i < 256; i++)
  923.     {
  924.       Red[i] = Green[i] = Blue[i] = i;
  925.     }
  926.       break;
  927.  
  928.     default:
  929.       g_message (_("GIF: Sorry, can't save RGB images as GIFs - convert to INDEXED\nor GRAY first.\n"));
  930.       return FALSE;
  931.       break;
  932.     }
  933.  
  934.   if (run_mode != GIMP_RUN_NONINTERACTIVE)
  935.     {
  936.       /* init the progress meter */    
  937.       temp_buf = g_strdup_printf (_("Saving %s:"), filename);
  938.       gimp_progress_init (temp_buf);
  939.       g_free (temp_buf);
  940.     }
  941.   
  942.  
  943.   /* open the destination file for writing */
  944.   outfile = fopen (filename, "wb");
  945.   if (!outfile)
  946.     {
  947.       g_message (_("GIF: can't open %s\n"), filename);
  948.       return FALSE;
  949.     }
  950.  
  951.  
  952.   /* write the GIFheader */
  953.  
  954.   if (colors < 256)
  955.     {
  956.       /* we keep track of how many bits we promised to have in liberalBPP,
  957.      so that we don't accidentally come under this when doing
  958.      clever transparency stuff where we can re-use wasted indices. */
  959.       liberalBPP = BitsPerPixel =
  960.     colorstobpp (colors + ((drawable_type==GIMP_INDEXEDA_IMAGE) ? 1 : 0));
  961.     }
  962.   else
  963.     {
  964.       liberalBPP = BitsPerPixel =
  965.     colorstobpp (256);
  966.  
  967.       if (drawable_type==GIMP_INDEXEDA_IMAGE)
  968.     {
  969.       g_print ("GIF: Too many colours?\n");
  970.     }
  971.     }
  972.  
  973.   cols = gimp_image_width (image_ID);
  974.   rows = gimp_image_height (image_ID);
  975.   Interlace = gsvals.interlace;
  976.   GIFEncodeHeader (outfile, is_gif89, cols, rows, 0,
  977.            BitsPerPixel, Red, Green, Blue, GetPixel);
  978.  
  979.  
  980.   /* If the image has multiple layers it'll be made into an
  981.      animated GIF, so write out the infinite-looping extension */
  982.   if ((nlayers > 1) && (gsvals.loop))
  983.     GIFEncodeLoopExt (outfile, 0);
  984.  
  985.   /* Write comment extension - mustn't be written before the looping ext. */
  986.   if (gsvals.save_comment)
  987.     {
  988.       GIFEncodeCommentExt (outfile, globalcomment);
  989.     }
  990.  
  991.  
  992.  
  993.   /*** Now for each layer in the image, save an image in a compound GIF ***/
  994.   /************************************************************************/
  995.  
  996.   i = nlayers-1;
  997.  
  998.   while (i >= 0)
  999.     {
  1000.       drawable_type = gimp_drawable_type (layers[i]);
  1001.       drawable = gimp_drawable_get (layers[i]);
  1002.       gimp_drawable_offsets (layers[i], &offset_x, &offset_y);
  1003.       cols = drawable->width;
  1004.       rows = drawable->height;
  1005.       rowstride = drawable->width;
  1006.       
  1007.       gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0,
  1008.                drawable->width, drawable->height, FALSE, FALSE);
  1009.  
  1010.       cur_progress = 0;
  1011.       max_progress = drawable->height;
  1012.       
  1013.       pixels = (guchar *) g_malloc (drawable->width *
  1014.                     drawable->height *
  1015.                     (((drawable_type == GIMP_INDEXEDA_IMAGE)||
  1016.                       (drawable_type == GIMP_GRAYA_IMAGE)) ? 2:1) );
  1017.       
  1018.       gimp_pixel_rgn_get_rect (&pixel_rgn, pixels, 0, 0,
  1019.                    drawable->width, drawable->height);
  1020.  
  1021.  
  1022.       /* sort out whether we need to do transparency jiggery-pokery */
  1023.       if ((drawable_type == GIMP_INDEXEDA_IMAGE)||(drawable_type == GIMP_GRAYA_IMAGE))
  1024.     {
  1025.       /* Try to find an entry which isn't actually used in the
  1026.          image, for a transparency index. */
  1027.       
  1028.       transparent =
  1029.         find_unused_ia_colour(pixels,
  1030.                   drawable->width * drawable->height,
  1031.                   bpptocolors(colorstobpp(colors)),
  1032.                   &colors);
  1033.  
  1034.       special_flatten_indexed_alpha (pixels,
  1035.                      &transparent,
  1036.                      &colors,
  1037.                      drawable->width * drawable->height);
  1038.     }
  1039.       else
  1040.     transparent = -1;
  1041.       
  1042.       
  1043.       BitsPerPixel = colorstobpp (colors);
  1044.  
  1045.       if (BitsPerPixel != liberalBPP)
  1046.     {
  1047.       /* We were able to re-use an index within the existing bitspace,
  1048.          whereas the estimate in the header was pessimistic but still
  1049.          needs to be upheld... */
  1050. #ifdef GIFDEBUG
  1051.       g_warning("Promised %d bpp, pondered writing chunk with %d bpp!",
  1052.             liberalBPP, BitsPerPixel);
  1053. #endif
  1054.       g_warning ("Transparent colour *might* be incorrect "
  1055.               "on viewers which don't support transparency.");
  1056.     }
  1057.       useBPP = (BitsPerPixel > liberalBPP) ? BitsPerPixel : liberalBPP;
  1058.  
  1059.       
  1060.       if (is_gif89)
  1061.     {
  1062.       if (i>0)
  1063.         {
  1064.           layer_name = gimp_layer_get_name(layers[i-1]);
  1065.           Disposal = parse_disposal_tag(layer_name);
  1066.           g_free(layer_name);
  1067.         }
  1068.       else
  1069.         Disposal = gsvals.default_dispose;
  1070.  
  1071.       layer_name = gimp_layer_get_name(layers[i]);
  1072.       Delay89 = parse_ms_tag(layer_name);
  1073.       g_free(layer_name);
  1074.  
  1075.       if (Delay89 < 0)
  1076.         Delay89 = (gsvals.default_delay + 5) / 10;
  1077.       else
  1078.         Delay89 = (Delay89 + 5) / 10;
  1079.  
  1080.       /* don't allow a CPU-sucking completely 0-delay looping anim */
  1081.       if ((nlayers > 1) &&
  1082.           gsvals.loop &&
  1083.           (Delay89 == 0))
  1084.         {
  1085.           static gboolean onceonly = FALSE;
  1086.  
  1087.           if (!onceonly)
  1088.         {
  1089.           g_warning("GIF plugin: Delay inserted to prevent evil "
  1090.                 "CPU-sucking anim.\n");
  1091.           onceonly = TRUE;
  1092.         }
  1093.           Delay89 = 1;
  1094.         }
  1095.  
  1096.       GIFEncodeGraphicControlExt (outfile, Disposal, Delay89, nlayers,
  1097.                       cols, rows, 0,
  1098.                       transparent,
  1099.                       useBPP,
  1100.                       Red, Green,
  1101.                       Blue, GetPixel);
  1102.     }
  1103.  
  1104.       GIFEncodeImageData (outfile, cols, rows,
  1105.               (rows>4) ? gsvals.interlace : 0,
  1106.               0, transparent,
  1107.               useBPP,
  1108.               Red, Green, Blue, GetPixel,
  1109.               offset_x, offset_y);
  1110.  
  1111.       
  1112.       
  1113.       gimp_drawable_detach (drawable);
  1114.       
  1115.       g_free (pixels);
  1116.  
  1117.       i--;
  1118.     }
  1119.   
  1120.   g_free(layers);
  1121.  
  1122.   GIFEncodeClose (outfile, cols, rows, gsvals.interlace, 0, transparent,
  1123.           useBPP, Red, Green, Blue, GetPixel);
  1124.  
  1125.   return TRUE;
  1126. }
  1127.  
  1128. static gboolean
  1129. badbounds_dialog (void)
  1130. {
  1131.   GtkWidget *dlg;
  1132.   GtkWidget *label;
  1133.   GtkWidget *frame;
  1134.   GtkWidget *vbox;
  1135.  
  1136.   dlg = gimp_dialog_new (_("GIF Warning"), "gif_warning",
  1137.              gimp_standard_help_func, "filters/gif.html#warning",
  1138.              GTK_WIN_POS_MOUSE,
  1139.              FALSE, FALSE, FALSE,
  1140.  
  1141.              _("OK"), cropok_callback,
  1142.              NULL, NULL, NULL, TRUE, FALSE,
  1143.              _("Cancel"), gtk_widget_destroy,
  1144.              NULL, 1, NULL, FALSE, TRUE,
  1145.  
  1146.              NULL);
  1147.  
  1148.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  1149.               GTK_SIGNAL_FUNC (gtk_main_quit),
  1150.               NULL);
  1151.  
  1152.   /*  the warning message  */
  1153.   frame = gtk_frame_new (NULL);
  1154.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  1155.   gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
  1156.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), frame, TRUE, TRUE, 0);
  1157.  
  1158.   vbox = gtk_vbox_new (FALSE, 4);
  1159.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
  1160.   gtk_container_add (GTK_CONTAINER (frame), vbox);
  1161.   
  1162.   label= gtk_label_new (_("The image which you are trying to save as a GIF\n"
  1163.               "contains layers which extend beyond the actual\n"
  1164.               "borders of the image.  This isn't allowed in GIFs,\n"
  1165.               "I'm afraid.\n\n"
  1166.               "You may choose whether to crop all of the layers to\n"
  1167.               "the image borders, or cancel this save."));
  1168.   gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
  1169.   gtk_widget_show (label);
  1170.  
  1171.   gtk_widget_show (vbox);
  1172.   gtk_widget_show (frame);
  1173.  
  1174.   gtk_widget_show (dlg);
  1175.  
  1176.   gtk_main ();
  1177.   gdk_flush ();
  1178.  
  1179.   return can_crop;
  1180. }
  1181.  
  1182.  
  1183. static gint
  1184. save_dialog (gint32 image_ID)
  1185. {
  1186.   GtkWidget *dlg;
  1187.   GtkWidget *main_vbox;
  1188.   GtkWidget *toggle;
  1189.   GtkWidget *label;
  1190.   GtkWidget *spinbutton;
  1191.   GtkObject *adj;
  1192.   GtkWidget *text;
  1193.   GtkWidget *frame;
  1194.   GtkWidget *vbox;
  1195.   GtkWidget *hbox;
  1196.   GtkWidget *disposal_option_menu;
  1197.   GtkWidget *com_table;
  1198.   GtkWidget *vscrollbar;
  1199. #ifdef FACEHUGGERS
  1200.   GimpParasite* GIF2_CMNT;
  1201. #endif
  1202.  
  1203.   gint32 nlayers;
  1204.  
  1205.   gimp_image_get_layers (image_ID, &nlayers);
  1206.  
  1207.   dlg = gimp_dialog_new (_("Save as GIF"), "gif",
  1208.              gimp_standard_help_func, "filters/gif.html",
  1209.              GTK_WIN_POS_MOUSE,
  1210.              FALSE, TRUE, FALSE,
  1211.  
  1212.              _("OK"), save_ok_callback,
  1213.              NULL, NULL, NULL, TRUE, FALSE,
  1214.              _("Cancel"), gtk_widget_destroy,
  1215.              NULL, 1, NULL, FALSE, TRUE,
  1216.  
  1217.              NULL);
  1218.  
  1219.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  1220.               GTK_SIGNAL_FUNC (gtk_main_quit),
  1221.               NULL);
  1222.  
  1223.   main_vbox = gtk_vbox_new (FALSE, 4);
  1224.   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6);
  1225.   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dlg)->vbox), main_vbox);
  1226.   gtk_widget_show (main_vbox);
  1227.  
  1228.   /*  regular gif parameter settings  */
  1229.   frame = gtk_frame_new (_("GIF Options"));
  1230.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  1231.   gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
  1232.  
  1233.   vbox = gtk_vbox_new (FALSE, 4);
  1234.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
  1235.   gtk_container_add (GTK_CONTAINER (frame), vbox);
  1236.  
  1237.   toggle = gtk_check_button_new_with_label (_("Interlace"));
  1238.   gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
  1239.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  1240.               GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  1241.               &gsvals.interlace);
  1242.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), gsvals.interlace);
  1243.   gtk_widget_show (toggle);
  1244.  
  1245.   hbox = gtk_hbox_new (FALSE, 4);
  1246.   gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
  1247.  
  1248.   toggle = gtk_check_button_new_with_label (_("GIF Comment:"));
  1249.   gtk_box_pack_start (GTK_BOX (hbox), toggle, FALSE, FALSE, 0);
  1250.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  1251.               GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  1252.               &gsvals.save_comment);
  1253.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), gsvals.save_comment);
  1254.   gtk_widget_show (toggle);
  1255.  
  1256.   com_table = gtk_table_new (1, 1, FALSE);
  1257.   gtk_box_pack_start (GTK_BOX (hbox), com_table, TRUE, TRUE, 0);
  1258.  
  1259.   text = gtk_text_new (NULL, NULL);
  1260.   gtk_text_set_editable (GTK_TEXT (text), TRUE);
  1261.   gtk_widget_set_usize (text, 80,3);
  1262.   gtk_table_attach (GTK_TABLE (com_table), text, 0, 1, 0, 1,
  1263.                     GTK_EXPAND | GTK_SHRINK | GTK_FILL,
  1264.                     GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
  1265.   
  1266.   if (globalcomment != NULL)
  1267.     {
  1268.       g_free (globalcomment);
  1269.     }
  1270. #ifdef FACEHUGGERS
  1271.   GIF2_CMNT = gimp_image_parasite_find (image_ID, "gimp-comment");
  1272.   if (GIF2_CMNT)
  1273.     {
  1274.       globalcomment = g_malloc (GIF2_CMNT->size+1);
  1275.       memcpy (globalcomment, GIF2_CMNT->data, GIF2_CMNT->size);
  1276.       globalcomment[GIF2_CMNT->size] = 0;
  1277.     }
  1278.   else
  1279.     {
  1280. #endif
  1281.       /*    globalcomment = g_malloc(1+strlen(_("Made with GIMP")));
  1282.         strcpy(globalcomment, _("Made with GIMP")); */
  1283.       globalcomment = NULL;
  1284. #ifdef FACEHUGGERS
  1285.     }
  1286.   gimp_parasite_free (GIF2_CMNT);
  1287. #endif
  1288.  
  1289.   if (globalcomment)
  1290.     gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, globalcomment, -1);
  1291.   gtk_signal_connect (GTK_OBJECT (text), "changed",
  1292.               GTK_SIGNAL_FUNC (comment_entry_callback),
  1293.               NULL);
  1294.  
  1295.   vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
  1296.   gtk_table_attach (GTK_TABLE (com_table), vscrollbar, 1, 2, 0, 1,
  1297.             GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
  1298.   gtk_widget_show (vscrollbar);
  1299.   gtk_widget_show (text);
  1300.   gtk_widget_show (com_table);
  1301.  
  1302.   gtk_widget_show (hbox);
  1303.  
  1304.   gtk_widget_show (vbox);
  1305.   gtk_widget_show (frame);
  1306.  
  1307.   /*  additional animated gif parameter settings  */
  1308.   frame = gtk_frame_new (_("Animated GIF Options"));
  1309.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  1310.   gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
  1311.  
  1312.   vbox = gtk_vbox_new (FALSE, 4);
  1313.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
  1314.   gtk_container_add (GTK_CONTAINER (frame), vbox);
  1315.  
  1316.   toggle = gtk_check_button_new_with_label (_("Loop forever"));
  1317.   gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
  1318.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  1319.               GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  1320.               &gsvals.loop);
  1321.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), gsvals.loop);
  1322.   gtk_widget_show (toggle);
  1323.  
  1324.   /* default_delay entry field */
  1325.   hbox = gtk_hbox_new (FALSE, 4);
  1326.   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
  1327.  
  1328.   label = gtk_label_new (_("Delay between Frames where Unspecified:"));
  1329.   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
  1330.   gtk_widget_show (label);
  1331.  
  1332.   spinbutton = gimp_spin_button_new (&adj, gsvals.default_delay,
  1333.                      0, 65000, 10, 100, 0, 1, 0);
  1334.   gtk_box_pack_start (GTK_BOX (hbox), spinbutton, FALSE, FALSE, 0);
  1335.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  1336.                       GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  1337.                       &gsvals.default_delay);
  1338.   gtk_widget_show (spinbutton);
  1339.  
  1340.   label = gtk_label_new (_("Milliseconds"));
  1341.   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
  1342.   gtk_widget_show (label);
  1343.  
  1344.   gtk_widget_show (hbox);
  1345.  
  1346.   /* Disposal selector */
  1347.   hbox = gtk_hbox_new (FALSE, 4);
  1348.   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
  1349.  
  1350.   label = gtk_label_new (_("Frame Disposal where Unspecified: "));
  1351.   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
  1352.   gtk_widget_show (label);
  1353.  
  1354.   disposal_option_menu =
  1355.     gimp_option_menu_new2 (FALSE, gimp_menu_item_update,
  1356.                &gsvals.default_dispose,
  1357.                GINT_TO_POINTER (gsvals.default_dispose),
  1358.  
  1359.                _("I don't Care"),
  1360.                GINT_TO_POINTER (DISPOSE_UNSPECIFIED), NULL,
  1361.                _("Cumulative Layers (Combine)"),
  1362.                GINT_TO_POINTER (DISPOSE_COMBINE), NULL,
  1363.                _("One Frame per Layer (Replace)"),
  1364.                GINT_TO_POINTER (DISPOSE_REPLACE), NULL,
  1365.  
  1366.                NULL);
  1367.   gtk_box_pack_start (GTK_BOX (hbox), disposal_option_menu, FALSE, FALSE, 0);
  1368.   gtk_widget_show (disposal_option_menu);
  1369.  
  1370.   gtk_widget_show (hbox);
  1371.   gtk_widget_show (vbox);
  1372.  
  1373.   /* If the image has only one layer it can't be animated, so
  1374.      desensitize the animation options. */
  1375.  
  1376.   if (nlayers == 1) gtk_widget_set_sensitive (frame, FALSE);
  1377.  
  1378.   gtk_widget_show (frame);
  1379.  
  1380.   gtk_widget_show (dlg);
  1381.  
  1382.   gtk_main ();
  1383.   gdk_flush ();
  1384.  
  1385.   return gsint.run;
  1386. }
  1387.  
  1388.  
  1389. static int
  1390. colorstobpp (int colors)
  1391. {
  1392.   int bpp;
  1393.  
  1394.   if (colors <= 2)
  1395.     bpp = 1;
  1396.   else if (colors <= 4)
  1397.     bpp = 2;
  1398.   else if (colors <= 8)
  1399.     bpp = 3;
  1400.   else if (colors <= 16)
  1401.     bpp = 4;
  1402.   else if (colors <= 32)
  1403.     bpp = 5;
  1404.   else if (colors <= 64)
  1405.     bpp = 6;
  1406.   else if (colors <= 128)
  1407.     bpp = 7;
  1408.   else if (colors <= 256)
  1409.     bpp = 8;
  1410.   else
  1411.     {
  1412.       g_warning ("GIF: colorstobpp - Eep! too many colours: %d\n", colors);
  1413.       return 8;
  1414.     }
  1415.  
  1416.   return bpp;
  1417. }
  1418.  
  1419.  
  1420.  
  1421. static int
  1422. bpptocolors (int bpp)
  1423. {
  1424.   int colors;
  1425.  
  1426.   if (bpp>8)
  1427.     {
  1428.       g_warning ("GIF: bpptocolors - Eep! bpp==%d !\n", bpp);
  1429.       return 256;
  1430.     }
  1431.   
  1432.   colors = 1 << bpp;
  1433.  
  1434.   return (colors);
  1435. }
  1436.  
  1437.  
  1438.  
  1439. static int
  1440. GetPixel (int x,
  1441.       int y)
  1442. {
  1443.   return *(pixels + (rowstride * (long) y) + (long) x);
  1444. }
  1445.  
  1446.  
  1447. /*****************************************************************************
  1448.  *
  1449.  * GIFENCODE.C    - GIF Image compression interface
  1450.  *
  1451.  * GIFEncode( FName, GHeight, GWidth, GInterlace, Background, Transparent,
  1452.  *            BitsPerPixel, Red, Green, Blue, GetPixel )
  1453.  *
  1454.  *****************************************************************************/
  1455.  
  1456. static gint  Width, Height;
  1457. static gint  curx, cury;
  1458. static glong CountDown;
  1459. static gint  Pass = 0;
  1460.  
  1461. /*
  1462.  * Bump the 'curx' and 'cury' to point to the next pixel
  1463.  */
  1464. static void
  1465. BumpPixel (void)
  1466. {
  1467.   /*
  1468.    * Bump the current X position
  1469.    */
  1470.   curx++;
  1471.  
  1472.   /*
  1473.    * If we are at the end of a scan line, set curx back to the beginning
  1474.    * If we are interlaced, bump the cury to the appropriate spot,
  1475.    * otherwise, just increment it.
  1476.    */
  1477.   if (curx == Width)
  1478.     {
  1479.       if (run_mode != GIMP_RUN_NONINTERACTIVE)
  1480.     {
  1481.       cur_progress++;
  1482.       if ((cur_progress % 16) == 0)
  1483.         gimp_progress_update ((double) cur_progress / (double) max_progress);
  1484.     }
  1485.  
  1486.       curx = 0;
  1487.  
  1488.       if (!Interlace)
  1489.     ++cury;
  1490.       else
  1491.     {
  1492.       switch (Pass)
  1493.         {
  1494.  
  1495.         case 0:
  1496.           cury += 8;
  1497.           if (cury >= Height)
  1498.         {
  1499.           Pass++;
  1500.           cury = 4;
  1501.         }
  1502.           break;
  1503.  
  1504.         case 1:
  1505.           cury += 8;
  1506.           if (cury >= Height)
  1507.         {
  1508.           Pass++;
  1509.           cury = 2;
  1510.         }
  1511.           break;
  1512.  
  1513.         case 2:
  1514.           cury += 4;
  1515.           if (cury >= Height)
  1516.         {
  1517.           Pass++;
  1518.           cury = 1;
  1519.         }
  1520.           break;
  1521.  
  1522.         case 3:
  1523.           cury += 2;
  1524.           break;
  1525.         }
  1526.     }
  1527.     }
  1528. }
  1529.  
  1530. /*
  1531.  * Return the next pixel from the image
  1532.  */
  1533. static int
  1534. GIFNextPixel (ifunptr getpixel)
  1535. {
  1536.   int r;
  1537.  
  1538.   if (CountDown == 0)
  1539.     return EOF;
  1540.  
  1541.   --CountDown;
  1542.  
  1543.   r = (*getpixel) (curx, cury);
  1544.  
  1545.   BumpPixel ();
  1546.  
  1547.   return r;
  1548. }
  1549.  
  1550. /* public */
  1551.  
  1552. static void
  1553. GIFEncodeHeader (FILE    *fp,
  1554.          gboolean gif89,
  1555.          int      GWidth,
  1556.          int      GHeight,
  1557.          int      Background,
  1558.          int      BitsPerPixel,
  1559.          int      Red[],
  1560.          int      Green[],
  1561.          int      Blue[],
  1562.          ifunptr  GetPixel)
  1563. {
  1564.   int B;
  1565.   int RWidth, RHeight;
  1566.   int LeftOfs, TopOfs;
  1567.   int Resolution;
  1568.   int ColorMapSize;
  1569.   int InitCodeSize;
  1570.   int i;
  1571.  
  1572.   ColorMapSize = 1 << BitsPerPixel;
  1573.  
  1574.   RWidth = Width = GWidth;
  1575.   RHeight = Height = GHeight;
  1576.   LeftOfs = TopOfs = 0;
  1577.  
  1578.   Resolution = BitsPerPixel;
  1579.  
  1580.   /*
  1581.    * Calculate number of bits we are expecting
  1582.    */
  1583.   CountDown = (long) Width *(long) Height;
  1584.  
  1585.   /*
  1586.    * Indicate which pass we are on (if interlace)
  1587.    */
  1588.   Pass = 0;
  1589.  
  1590.   /*
  1591.    * The initial code size
  1592.    */
  1593.   if (BitsPerPixel <= 1)
  1594.     InitCodeSize = 2;
  1595.   else
  1596.     InitCodeSize = BitsPerPixel;
  1597.  
  1598.   /*
  1599.    * Set up the current x and y position
  1600.    */
  1601.   curx = cury = 0;
  1602.  
  1603.   /*
  1604.    * Write the Magic header
  1605.    */
  1606.   fwrite (gif89 ? "GIF89a" : "GIF87a", 1, 6, fp);
  1607.  
  1608.   /*
  1609.    * Write out the screen width and height
  1610.    */
  1611.   Putword (RWidth, fp);
  1612.   Putword (RHeight, fp);
  1613.  
  1614.   /*
  1615.    * Indicate that there is a global colour map
  1616.    */
  1617.   B = 0x80;            /* Yes, there is a color map */
  1618.  
  1619.   /*
  1620.    * OR in the resolution
  1621.    */
  1622.   B |= (Resolution - 1) << 5;
  1623.  
  1624.   /*
  1625.    * OR in the Bits per Pixel
  1626.    */
  1627.   B |= (BitsPerPixel - 1);
  1628.  
  1629.   /*
  1630.    * Write it out
  1631.    */
  1632.   fputc (B, fp);
  1633.  
  1634.   /*
  1635.    * Write out the Background colour
  1636.    */
  1637.   fputc (Background, fp);
  1638.  
  1639.   /*
  1640.    * Byte of 0's (future expansion)
  1641.    */
  1642.   fputc (0, fp);
  1643.  
  1644.   /*
  1645.    * Write out the Global Colour Map
  1646.    */
  1647.   for (i = 0; i < ColorMapSize; i++)
  1648.     {
  1649.       fputc (Red[i], fp);
  1650.       fputc (Green[i], fp);
  1651.       fputc (Blue[i], fp);
  1652.     }
  1653. }
  1654.  
  1655.  
  1656. static void
  1657. GIFEncodeGraphicControlExt (FILE    *fp,
  1658.                 int      Disposal,
  1659.                 int      Delay89,
  1660.                 int      NumFramesInImage,
  1661.                 int      GWidth,
  1662.                 int      GHeight,
  1663.                 int      Background,
  1664.                 int      Transparent,
  1665.                 int      BitsPerPixel,
  1666.                 int      Red[],
  1667.                 int      Green[],
  1668.                 int      Blue[],
  1669.                 ifunptr  GetPixel)
  1670. {
  1671.   int RWidth, RHeight;
  1672.   int LeftOfs, TopOfs;
  1673.   int Resolution;
  1674.   int ColorMapSize;
  1675.   int InitCodeSize;
  1676.  
  1677.   ColorMapSize = 1 << BitsPerPixel;
  1678.  
  1679.   RWidth = Width = GWidth;
  1680.   RHeight = Height = GHeight;
  1681.   LeftOfs = TopOfs = 0;
  1682.  
  1683.   Resolution = BitsPerPixel;
  1684.  
  1685.   /*
  1686.    * Calculate number of bits we are expecting
  1687.    */
  1688.   CountDown = (long) Width *(long) Height;
  1689.  
  1690.   /*
  1691.    * Indicate which pass we are on (if interlace)
  1692.    */
  1693.   Pass = 0;
  1694.  
  1695.   /*
  1696.    * The initial code size
  1697.    */
  1698.   if (BitsPerPixel <= 1)
  1699.     InitCodeSize = 2;
  1700.   else
  1701.     InitCodeSize = BitsPerPixel;
  1702.  
  1703.   /*
  1704.    * Set up the current x and y position
  1705.    */
  1706.   curx = cury = 0;
  1707.  
  1708.   /*
  1709.    * Write out extension for transparent colour index, if necessary.
  1710.    */
  1711.   if ( (Transparent >= 0) || (NumFramesInImage > 1) )
  1712.     {
  1713.       /* Extension Introducer - fixed. */
  1714.       fputc ('!', fp);
  1715.       /* Graphic Control Label - fixed. */
  1716.       fputc (0xf9, fp);
  1717.       /* Block Size - fixed. */
  1718.       fputc (4, fp);
  1719.       
  1720.       /* Packed Fields - XXXdddut (d=disposal, u=userInput, t=transFlag) */
  1721.       /*                    s8421                                        */
  1722.       fputc ( ((Transparent >= 0) ? 0x01 : 0x00) /* TRANSPARENCY */
  1723.  
  1724.           /* DISPOSAL */
  1725.           | ((NumFramesInImage > 1) ? (Disposal << 2) : 0x00 ),
  1726.           /* 0x03 or 0x01 build frames cumulatively */
  1727.           /* 0x02 clears frame before drawing */
  1728.           /* 0x00 'don't care' */
  1729.  
  1730.           fp);
  1731.       
  1732.       fputc (Delay89 & 255, fp);
  1733.       fputc ((Delay89>>8) & 255, fp);
  1734.  
  1735.       fputc (Transparent, fp);
  1736.       fputc (0, fp);
  1737.     }
  1738. }
  1739.  
  1740.  
  1741. static void
  1742. GIFEncodeImageData (FILE    *fp,
  1743.             int      GWidth,
  1744.             int      GHeight,
  1745.             int      GInterlace,
  1746.             int      Background,
  1747.             int      Transparent,
  1748.             int      BitsPerPixel,
  1749.             int      Red[],
  1750.             int      Green[],
  1751.             int      Blue[],
  1752.             ifunptr  GetPixel,
  1753.             gint     offset_x,
  1754.             gint     offset_y)
  1755. {
  1756.   int RWidth, RHeight;
  1757.   int LeftOfs, TopOfs;
  1758.   int Resolution;
  1759.   int ColorMapSize;
  1760.   int InitCodeSize;
  1761.  
  1762.   Interlace = GInterlace;
  1763.  
  1764.   ColorMapSize = 1 << BitsPerPixel;
  1765.  
  1766.   RWidth = Width = GWidth;
  1767.   RHeight = Height = GHeight;
  1768.   LeftOfs = (int) offset_x;
  1769.   TopOfs = (int) offset_y;
  1770.  
  1771.   Resolution = BitsPerPixel;
  1772.  
  1773.   /*
  1774.    * Calculate number of bits we are expecting
  1775.    */
  1776.   CountDown = (long) Width *(long) Height;
  1777.  
  1778.   /*
  1779.    * Indicate which pass we are on (if interlace)
  1780.    */
  1781.   Pass = 0;
  1782.  
  1783.   /*
  1784.    * The initial code size
  1785.    */
  1786.   if (BitsPerPixel <= 1)
  1787.     InitCodeSize = 2;
  1788.   else
  1789.     InitCodeSize = BitsPerPixel;
  1790.  
  1791.   /*
  1792.    * Set up the current x and y position
  1793.    */
  1794.   curx = cury = 0;
  1795.  
  1796. #if 0
  1797.   /*
  1798.    * Write an Image separator
  1799.    */
  1800.   fputc (',', fp);
  1801.  
  1802.   /*
  1803.    * Write the Image header
  1804.    */
  1805.  
  1806.   Putword (LeftOfs, fp);
  1807.   Putword (TopOfs, fp);
  1808.   Putword (Width, fp);
  1809.   Putword (Height, fp);
  1810.  
  1811.   /*
  1812.    * Write out whether or not the image is interlaced
  1813.    */
  1814.   if (Interlace)
  1815.     fputc (0x40, fp);
  1816.   else
  1817.     fputc (0x00, fp);
  1818.  
  1819.   /*
  1820.    * Write out the initial code size
  1821.    */
  1822.   fputc (InitCodeSize, fp);
  1823.  
  1824.   /*
  1825.    * Go and actually compress the data
  1826.    */
  1827.   compress (InitCodeSize + 1, fp, GetPixel);
  1828.  
  1829.   /*
  1830.    * Write out a Zero-length packet (to end the series)
  1831.    */
  1832.   fputc (0, fp);
  1833.  
  1834.  
  1835.   /***************************/
  1836.   Interlace = GInterlace;
  1837.   ColorMapSize = 1 << BitsPerPixel;
  1838.   RWidth = Width = GWidth;
  1839.   RHeight = Height = GHeight;
  1840.   LeftOfs = TopOfs = 0;
  1841.   Resolution = BitsPerPixel;
  1842.  
  1843.   CountDown = (long) Width *(long) Height;
  1844.   Pass = 0;
  1845.   /*
  1846.    * The initial code size
  1847.    */
  1848.   if (BitsPerPixel <= 1)
  1849.     InitCodeSize = 2;
  1850.   else
  1851.     InitCodeSize = BitsPerPixel;
  1852.   /*
  1853.    * Set up the current x and y position
  1854.    */
  1855.   curx = cury = 0;
  1856.  
  1857. #endif
  1858.  
  1859.  
  1860.   cur_progress = 0;
  1861.  
  1862.  
  1863.   /*
  1864.    * Write an Image separator
  1865.    */
  1866.   fputc (',', fp);
  1867.  
  1868.   /*
  1869.    * Write the Image header
  1870.    */
  1871.  
  1872.   Putword (LeftOfs, fp);
  1873.   Putword (TopOfs, fp);
  1874.   Putword (Width, fp);
  1875.   Putword (Height, fp);
  1876.  
  1877.   /*
  1878.    * Write out whether or not the image is interlaced
  1879.    */
  1880.   if (Interlace)
  1881.     fputc (0x40, fp);
  1882.   else
  1883.     fputc (0x00, fp);
  1884.  
  1885.   /*
  1886.    * Write out the initial code size
  1887.    */
  1888.   fputc (InitCodeSize, fp);
  1889.  
  1890.   /*
  1891.    * Go and actually compress the data
  1892.    */
  1893.   compress (InitCodeSize + 1, fp, GetPixel);
  1894.  
  1895.   /*
  1896.    * Write out a Zero-length packet (to end the series)
  1897.    */
  1898.   fputc (0, fp);
  1899. }
  1900.  
  1901.  
  1902. static void
  1903. GIFEncodeClose (FILE    *fp,
  1904.         int      GWidth,
  1905.         int      GHeight,
  1906.         int      GInterlace,
  1907.         int      Background,
  1908.         int      Transparent,
  1909.         int      BitsPerPixel,
  1910.         int      Red[],
  1911.         int      Green[],
  1912.         int      Blue[],
  1913.         ifunptr  GetPixel)
  1914. {
  1915.   /*
  1916.    * Write the GIF file terminator
  1917.    */
  1918.   fputc (';', fp);
  1919.  
  1920.   /*
  1921.    * And close the file
  1922.    */
  1923.   fclose (fp);
  1924. }
  1925.  
  1926.  
  1927. static void
  1928. GIFEncodeLoopExt (FILE    *fp,
  1929.           guint    num_loops)
  1930. {
  1931.   fputc(0x21,fp);
  1932.   fputc(0xff,fp);
  1933.   fputc(0x0b,fp);
  1934.   fputs("NETSCAPE2.0",fp);
  1935.   fputc(0x03,fp);
  1936.   fputc(0x01,fp);
  1937.   Putword(num_loops,fp);
  1938.   fputc(0x00,fp);
  1939.  
  1940.   /* NOTE: num_loops==0 means 'loop infinitely' */
  1941. }
  1942.  
  1943.  
  1944. static void GIFEncodeCommentExt (FILE *fp, char *comment)
  1945. {
  1946.   if (!comment || !*comment)
  1947.     return;
  1948.  
  1949.   if (strlen(comment)>240)
  1950.     {
  1951.       g_print ("GIF: warning: comment too large - comment block not written.\n");
  1952.       return;
  1953.     }
  1954.  
  1955.   fputc(0x21,fp);
  1956.   fputc(0xfe,fp);
  1957.   fputc(strlen(comment),fp);
  1958.   fputs((const char *)comment,fp);
  1959.   fputc(0x00,fp);
  1960. }
  1961.  
  1962.  
  1963.  
  1964. /*
  1965.  * Write out a word to the GIF file
  1966.  */
  1967. static void
  1968. Putword (int   w,
  1969.      FILE *fp)
  1970. {
  1971.   fputc (w & 0xff, fp);
  1972.   fputc ((w / 256) & 0xff, fp);
  1973. }
  1974.  
  1975.  
  1976. /***************************************************************************
  1977.  *
  1978.  *  GIFCOMPR.C       - GIF Image compression routines
  1979.  *
  1980.  *  Lempel-Ziv compression based on 'compress'.  GIF modifications by
  1981.  *  David Rowley (mgardi@watdcsu.waterloo.edu)
  1982.  *
  1983.  ***************************************************************************/
  1984.  
  1985. /*
  1986.  * General DEFINEs
  1987.  */
  1988.  
  1989. #define GIF_BITS    12
  1990.  
  1991. #define HSIZE  5003        /* 80% occupancy */
  1992.  
  1993. #ifdef NO_UCHAR
  1994. typedef char char_type;
  1995. #else /*NO_UCHAR */
  1996. typedef unsigned char char_type;
  1997. #endif /*NO_UCHAR */
  1998.  
  1999. /*
  2000.  
  2001.  * GIF Image compression - modified 'compress'
  2002.  *
  2003.  * Based on: compress.c - File compression ala IEEE Computer, June 1984.
  2004.  *
  2005.  * By Authors:  Spencer W. Thomas       (decvax!harpo!utah-cs!utah-gr!thomas)
  2006.  *              Jim McKie               (decvax!mcvax!jim)
  2007.  *              Steve Davies            (decvax!vax135!petsd!peora!srd)
  2008.  *              Ken Turkowski           (decvax!decwrl!turtlevax!ken)
  2009.  *              James A. Woods          (decvax!ihnp4!ames!jaw)
  2010.  *              Joe Orost               (decvax!vax135!petsd!joe)
  2011.  *
  2012.  */
  2013. #include <ctype.h>
  2014.  
  2015. #define ARGVAL() (*++(*argv) || (--argc && *++argv))
  2016.  
  2017. static int n_bits;        /* number of bits/code */
  2018. static int maxbits = GIF_BITS;    /* user settable max # bits/code */
  2019. static code_int maxcode;    /* maximum code, given n_bits */
  2020. static code_int maxmaxcode = (code_int) 1 << GIF_BITS;    /* should NEVER generate this code */
  2021. #ifdef COMPATIBLE        /* But wrong! */
  2022. #define MAXCODE(Mn_bits)        ((code_int) 1 << (Mn_bits) - 1)
  2023. #else /*COMPATIBLE */
  2024. #define MAXCODE(Mn_bits)        (((code_int) 1 << (Mn_bits)) - 1)
  2025. #endif /*COMPATIBLE */
  2026.  
  2027. static count_int htab[HSIZE];
  2028. static unsigned short codetab[HSIZE];
  2029. #define HashTabOf(i)       htab[i]
  2030. #define CodeTabOf(i)    codetab[i]
  2031.  
  2032. const code_int hsize = HSIZE;    /* the original reason for this being
  2033.                    variable was "for dynamic table sizing",
  2034.                    but since it was never actually changed
  2035.                    I made it const   --Adam. */
  2036.  
  2037. /*
  2038.  * To save much memory, we overlay the table used by compress() with those
  2039.  * used by decompress().  The tab_prefix table is the same size and type
  2040.  * as the codetab.  The tab_suffix table needs 2**GIF_BITS characters.  We
  2041.  * get this from the beginning of htab.  The output stack uses the rest
  2042.  * of htab, and contains characters.  There is plenty of room for any
  2043.  * possible stack (stack used to be 8000 characters).
  2044.  */
  2045.  
  2046. #define tab_prefixof(i) CodeTabOf(i)
  2047. #define tab_suffixof(i)        ((char_type*)(htab))[i]
  2048. #define de_stack               ((char_type*)&tab_suffixof((code_int)1<<GIF_BITS))
  2049.  
  2050. static code_int free_ent = 0;    /* first unused entry */
  2051.  
  2052. /*
  2053.  * block compression parameters -- after all codes are used up,
  2054.  * and compression rate changes, start over.
  2055.  */
  2056. static int clear_flg = 0;
  2057.  
  2058. static int offset;
  2059. static long int in_count = 1;    /* length of input */
  2060. static long int out_count = 0;    /* # of codes output (for debugging) */
  2061.  
  2062. /*
  2063.  * compress stdin to stdout
  2064.  *
  2065.  * Algorithm:  use open addressing double hashing (no chaining) on the
  2066.  * prefix code / next character combination.  We do a variant of Knuth's
  2067.  * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
  2068.  * secondary probe.  Here, the modular division first probe is gives way
  2069.  * to a faster exclusive-or manipulation.  Also do block compression with
  2070.  * an adaptive reset, whereby the code table is cleared when the compression
  2071.  * ratio decreases, but after the table fills.  The variable-length output
  2072.  * codes are re-sized at this point, and a special CLEAR code is generated
  2073.  * for the decompressor.  Late addition:  construct the table according to
  2074.  * file size for noticeable speed improvement on small files.  Please direct
  2075.  * questions about this implementation to ames!jaw.
  2076.  */
  2077.  
  2078. static int g_init_bits;
  2079. static FILE *g_outfile;
  2080.  
  2081. static int ClearCode;
  2082. static int EOFCode;
  2083.  
  2084.  
  2085. static unsigned long cur_accum;
  2086. static int cur_bits;
  2087.  
  2088. static unsigned long masks[] =
  2089. {0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
  2090.  0x001F, 0x003F, 0x007F, 0x00FF,
  2091.  0x01FF, 0x03FF, 0x07FF, 0x0FFF,
  2092.  0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF};
  2093.  
  2094.  
  2095. static void
  2096. compress (int      init_bits,
  2097.       FILE    *outfile,
  2098.       ifunptr  ReadValue)
  2099. {
  2100.   register long fcode;
  2101.   register code_int i /* = 0 */ ;
  2102.   register int c;
  2103.   register code_int ent;
  2104.   register code_int disp;
  2105.   register code_int hsize_reg;
  2106.   register int hshift;
  2107.  
  2108.  
  2109.   /*
  2110.    * Set up the globals:  g_init_bits - initial number of bits
  2111.    *                      g_outfile   - pointer to output file
  2112.    */
  2113.   g_init_bits = init_bits;
  2114.   g_outfile = outfile;
  2115.  
  2116.   cur_bits = 0;
  2117.   cur_accum = 0;
  2118.  
  2119.   /*
  2120.    * Set up the necessary values
  2121.    */
  2122.   offset = 0;
  2123.   out_count = 0;
  2124.   clear_flg = 0;
  2125.   in_count = 1;
  2126.  
  2127.   ClearCode = (1 << (init_bits - 1));
  2128.   EOFCode = ClearCode + 1;
  2129.   free_ent = ClearCode + 2;
  2130.  
  2131.  
  2132.   /* Had some problems here... should be okay now.  --Adam */
  2133.   n_bits = g_init_bits;
  2134.   maxcode = MAXCODE (n_bits);
  2135.  
  2136.  
  2137.  
  2138.   char_init ();
  2139.  
  2140.   ent = GIFNextPixel (ReadValue);
  2141.  
  2142.   hshift = 0;
  2143.   for (fcode = (long) hsize; fcode < 65536L; fcode *= 2L)
  2144.     ++hshift;
  2145.   hshift = 8 - hshift;        /* set hash code range bound */
  2146.  
  2147.   hsize_reg = hsize;
  2148.   cl_hash ((count_int) hsize_reg);    /* clear hash table */
  2149.  
  2150.   output ((code_int) ClearCode);
  2151.  
  2152.  
  2153. #ifdef SIGNED_COMPARE_SLOW
  2154.   while ((c = GIFNextPixel (ReadValue)) != (unsigned) EOF)
  2155.     {
  2156. #else /*SIGNED_COMPARE_SLOW */
  2157.   while ((c = GIFNextPixel (ReadValue)) != EOF)
  2158.     {                /* } */
  2159. #endif /*SIGNED_COMPARE_SLOW */
  2160.  
  2161.       ++in_count;
  2162.  
  2163.       fcode = (long) (((long) c << maxbits) + ent);
  2164.       i = (((code_int) c << hshift) ^ ent);    /* xor hashing */
  2165.  
  2166.       if (HashTabOf (i) == fcode)
  2167.     {
  2168.       ent = CodeTabOf (i);
  2169.       continue;
  2170.     }
  2171.       else if ((long) HashTabOf (i) < 0)    /* empty slot */
  2172.     goto nomatch;
  2173.       disp = hsize_reg - i;    /* secondary hash (after G. Knott) */
  2174.       if (i == 0)
  2175.     disp = 1;
  2176.     probe:
  2177.       if ((i -= disp) < 0)
  2178.     i += hsize_reg;
  2179.  
  2180.       if (HashTabOf (i) == fcode)
  2181.     {
  2182.       ent = CodeTabOf (i);
  2183.       continue;
  2184.     }
  2185.       if ((long) HashTabOf (i) > 0)
  2186.     goto probe;
  2187.     nomatch:
  2188.       output ((code_int) ent);
  2189.       ++out_count;
  2190.       ent = c;
  2191. #ifdef SIGNED_COMPARE_SLOW
  2192.       if ((unsigned) free_ent < (unsigned) maxmaxcode)
  2193.     {
  2194. #else /*SIGNED_COMPARE_SLOW */
  2195.       if (free_ent < maxmaxcode)
  2196.     {            /* } */
  2197. #endif /*SIGNED_COMPARE_SLOW */
  2198.       CodeTabOf (i) = free_ent++;    /* code -> hashtable */
  2199.       HashTabOf (i) = fcode;
  2200.     }
  2201.       else
  2202.     cl_block ();
  2203.     }
  2204.   /*
  2205.    * Put out the final code.
  2206.    */
  2207.   output ((code_int) ent);
  2208.   ++out_count;
  2209.   output ((code_int) EOFCode);
  2210. }
  2211.  
  2212. /*****************************************************************
  2213.  * TAG( output )
  2214.  *
  2215.  * Output the given code.
  2216.  * Inputs:
  2217.  *      code:   A n_bits-bit integer.  If == -1, then EOF.  This assumes
  2218.  *              that n_bits =< (long)wordsize - 1.
  2219.  * Outputs:
  2220.  *      Outputs code to the file.
  2221.  * Assumptions:
  2222.  *      Chars are 8 bits long.
  2223.  * Algorithm:
  2224.  *      Maintain a GIF_BITS character long buffer (so that 8 codes will
  2225.  * fit in it exactly).  Use the VAX insv instruction to insert each
  2226.  * code in turn.  When the buffer fills up empty it and start over.
  2227.  */
  2228.  
  2229. static void
  2230. output (code_int code)
  2231. {
  2232.   cur_accum &= masks[cur_bits];
  2233.  
  2234.   if (cur_bits > 0)
  2235.     cur_accum |= ((long) code << cur_bits);
  2236.   else
  2237.     cur_accum = code;
  2238.  
  2239.   cur_bits += n_bits;
  2240.  
  2241.   while (cur_bits >= 8)
  2242.     {
  2243.       char_out ((unsigned int) (cur_accum & 0xff));
  2244.       cur_accum >>= 8;
  2245.       cur_bits -= 8;
  2246.     }
  2247.  
  2248.   /*
  2249.    * If the next entry is going to be too big for the code size,
  2250.    * then increase it, if possible.
  2251.    */
  2252.   if (free_ent > maxcode || clear_flg)
  2253.     {
  2254.  
  2255.       if (clear_flg)
  2256.     {
  2257.  
  2258.       maxcode = MAXCODE (n_bits = g_init_bits);
  2259.       clear_flg = 0;
  2260.  
  2261.     }
  2262.       else
  2263.     {
  2264.  
  2265.       ++n_bits;
  2266.       if (n_bits == maxbits)
  2267.         maxcode = maxmaxcode;
  2268.       else
  2269.         maxcode = MAXCODE (n_bits);
  2270.     }
  2271.     }
  2272.  
  2273.   if (code == EOFCode)
  2274.     {
  2275.       /*
  2276.        * At EOF, write the rest of the buffer.
  2277.        */
  2278.       while (cur_bits > 0)
  2279.     {
  2280.       char_out ((unsigned int) (cur_accum & 0xff));
  2281.       cur_accum >>= 8;
  2282.       cur_bits -= 8;
  2283.     }
  2284.  
  2285.       flush_char ();
  2286.  
  2287.       fflush (g_outfile);
  2288.  
  2289.       if (ferror (g_outfile))
  2290.     writeerr ();
  2291.     }
  2292. }
  2293.  
  2294. /*
  2295.  * Clear out the hash table
  2296.  */
  2297. static void
  2298. cl_block ()            /* table clear for block compress */
  2299. {
  2300.  
  2301.   cl_hash ((count_int) hsize);
  2302.   free_ent = ClearCode + 2;
  2303.   clear_flg = 1;
  2304.  
  2305.   output ((code_int) ClearCode);
  2306. }
  2307.  
  2308. static void
  2309. cl_hash (register count_int hsize)            /* reset code table */
  2310. {
  2311.  
  2312.   register count_int *htab_p = htab + hsize;
  2313.  
  2314.   register long i;
  2315.   register long m1 = -1;
  2316.  
  2317.   i = hsize - 16;
  2318.   do
  2319.     {                /* might use Sys V memset(3) here */
  2320.       *(htab_p - 16) = m1;
  2321.       *(htab_p - 15) = m1;
  2322.       *(htab_p - 14) = m1;
  2323.       *(htab_p - 13) = m1;
  2324.       *(htab_p - 12) = m1;
  2325.       *(htab_p - 11) = m1;
  2326.       *(htab_p - 10) = m1;
  2327.       *(htab_p - 9) = m1;
  2328.       *(htab_p - 8) = m1;
  2329.       *(htab_p - 7) = m1;
  2330.       *(htab_p - 6) = m1;
  2331.       *(htab_p - 5) = m1;
  2332.       *(htab_p - 4) = m1;
  2333.       *(htab_p - 3) = m1;
  2334.       *(htab_p - 2) = m1;
  2335.       *(htab_p - 1) = m1;
  2336.       htab_p -= 16;
  2337.     }
  2338.   while ((i -= 16) >= 0);
  2339.  
  2340.   for (i += 16; i > 0; --i)
  2341.     *--htab_p = m1;
  2342. }
  2343.  
  2344. static void
  2345. writeerr ()
  2346. {
  2347.   g_message (_("GIF: error writing output file\n"));
  2348.   return;
  2349. }
  2350.  
  2351. /******************************************************************************
  2352.  *
  2353.  * GIF Specific routines
  2354.  *
  2355.  ******************************************************************************/
  2356.  
  2357. /*
  2358.  * Number of characters so far in this 'packet'
  2359.  */
  2360. static int a_count;
  2361.  
  2362. /*
  2363.  * Set up the 'byte output' routine
  2364.  */
  2365. static void
  2366. char_init ()
  2367. {
  2368.   a_count = 0;
  2369. }
  2370.  
  2371. /*
  2372.  * Define the storage for the packet accumulator
  2373.  */
  2374. static char accum[256];
  2375.  
  2376. /*
  2377.  * Add a character to the end of the current packet, and if it is 254
  2378.  * characters, flush the packet to disk.
  2379.  */
  2380. static void
  2381. char_out (int c)
  2382. {
  2383.   accum[a_count++] = c;
  2384.   if (a_count >= 254)
  2385.     flush_char ();
  2386. }
  2387.  
  2388. /*
  2389.  * Flush the packet to disk, and reset the accumulator
  2390.  */
  2391. static void
  2392. flush_char (void)
  2393. {
  2394.   if (a_count > 0)
  2395.     {
  2396.       fputc (a_count, g_outfile);
  2397.       fwrite (accum, 1, a_count, g_outfile);
  2398.       a_count = 0;
  2399.     }
  2400. }
  2401.  
  2402.  
  2403. /* crop dialog functions */
  2404.  
  2405. static void
  2406. cropok_callback (GtkWidget *widget,
  2407.          gpointer   data)
  2408. {
  2409.   can_crop = TRUE;
  2410.  
  2411.   gtk_widget_destroy (GTK_WIDGET (data));
  2412. }
  2413.  
  2414. /*  Save interface functions  */
  2415.  
  2416. static void
  2417. save_ok_callback (GtkWidget *widget,
  2418.           gpointer   data)
  2419. {
  2420.   gsint.run = TRUE;
  2421.  
  2422.   gtk_widget_destroy (GTK_WIDGET (data));
  2423. }
  2424.  
  2425. static void
  2426. comment_entry_callback (GtkWidget *widget,
  2427.             gpointer   data)
  2428. {
  2429.   gint ssize;
  2430.   gchar* str;
  2431.  
  2432.   str = gtk_editable_get_chars (GTK_EDITABLE (widget), 0, -1);
  2433.   ssize = strlen (str);
  2434.  
  2435.   /* Temporary kludge for overlength strings - just return */
  2436.   if (ssize > 240)
  2437.     {
  2438.       g_message (_("GIF save: Your comment string is too long.\n"));
  2439.       g_free (str);
  2440.       return;
  2441.     }
  2442.  
  2443.   if (globalcomment != NULL) g_free (globalcomment);
  2444.   globalcomment = g_malloc (ssize + 1);
  2445.  
  2446.   /*strcpy(globalcomment, gtk_entry_get_text (GTK_ENTRY (widget)));*/
  2447.   strcpy (globalcomment, str);
  2448.   g_free (str);
  2449.  
  2450.   comment_was_edited = TRUE;
  2451.  
  2452.   /*g_print ("COMMENT: %s\n",globalcomment);*/
  2453. }
  2454.